管理ポリシーの差分を出力する AWS CLI エイリアス aws diff を作ってみた
コンバンハ、千葉(幸)です。
管理ポリシー、特に AWS 管理ポリシーの変更差分を確認したい機会がたまにあります。
マネジメントコンソール上で差分表示するような機能があれば便利なのですが、現時点では実装されていません。
ないなら AWS CLI でやってみるか、ということでエイリアスを組んでみました。
管理ポリシーの差分を表示するエイリアス
以下のエイリアスを設定しました。
[toplevel] diff = !f() { VERSION=$(aws iam get-policy --policy-arn $1 --query 'Policy.DefaultVersionId' --output text | tr -d "v") BEFORE_VERSION=$((VERSION-1)) BEFORE_RESULT=$(aws iam get-policy-version --policy-arn $1 --version-id v$BEFORE_VERSION) AFTER_RESULT=$(aws iam get-policy-version --policy-arn $1 --version-id v$VERSION) echo $BEFORE_RESULT | jq .PolicyVersion.Document >> /tmp/policy_before echo $AFTER_RESULT | jq .PolicyVersion.Document >> /tmp/policy_after BEFORE_DATE=$(echo $BEFORE_RESULT | jq .PolicyVersion.CreateDate) AFTER_DATE=$(echo $AFTER_RESULT | jq .PolicyVersion.CreateDate) diff -C 0 --label "Version$BEFORE_VERSION:$BEFORE_DATE" --label "Version$VERSION:$AFTER_DATE" /tmp/policy_before /tmp/policy_after rm /tmp/policy_* }; f
このエイリアスに管理ポリシーの ARN を引数として渡してあげれば、直前のバージョンとの差分が表示されます。
$ aws diff arn:aws:iam::aws:policy/ReadOnlyAccess *** Version82:"2021-10-26T20:14:30+00:00" --- Version83:"2022-02-16T20:46:04+00:00" *************** *** 333 **** --- 334,335 ---- + "ec2:ListSnapshotsInRecycleBin", + "ec2:SearchLocalGatewayRoutes", *************** *** 372 **** --- 375,381 ---- + "emr-containers:DescribeJobRun", + "emr-containers:DescribeManagedEndpoint", + "emr-containers:DescribeVirtualCluster", + "emr-containers:ListJobRuns", + "emr-containers:ListManagedEndpoints", + "emr-containers:ListVirtualClusters", + "emr-containers:ListTagsForResource", *************** *** 561 **** --- 571,588 ---- + "iotroborunner:GetAction", + "iotroborunner:GetActionTemplate", + "iotroborunner:GetActivity", + "iotroborunner:GetDestination", + "iotroborunner:GetDestinationRelationship", ----------以下略----------
以下の前提を満たす環境であれば使用できるかと思います。AWS CloudShell では実行できました。
- AWS CLI エイリアスが使用できる
- jq が使用できる
- diff が使用できる
- 以下を実行可能な権限を持っている
- aws iam get-policy
- aws iam get-policy-version
管理ポリシーの差分を表示するエイリアスの流れ
上記のエイリアスによって大まかに以下が実行されます。
- 引数として指定したポリシーのデフォルトバージョンを取得
- デフォルトバージョン、その直前のバージョンのポリシーの内訳を取得
- ポリシードキュメントをtmpファイルに出力
- ポリシーバージョンの作成日時を取得
- tmpファイルを対象に diff を実施
- tmpファイルを削除
aws iam get-policy
デフォルトバージョンを取得するために実行します。
{ "Policy": { "PolicyName": "MySamplePolicy", "CreateDate": "2015-06-17T19:23;32Z", "AttachmentCount": 0, "IsAttachable": true, "PolicyId": "Z27SI6FQMGNQ2EXAMPLE1", "DefaultVersionId": "v1", "Path": "/", "Arn": "arn:aws:iam::123456789012:policy/MySamplePolicy", "UpdateDate": "2015-06-17T19:23:32Z" } }
今回は「デフォルトバージョン=最新バージョン」であろうという想定のもとエイリアスを組んでいます。AWS 管理ポリシーはその原則で考えて問題ないと思いますが、カスタマー管理ポリシーの場合は注意してください。
aws iam get-policy-version
ポリシードキュメント、バージョンの作成日時を取得するために実行します。
{ "PolicyVersion": { "CreateDate": "2015-06-17T19:23;32Z", "VersionId": "v2", "Document": { "Version": "2012-10-17", "Statement": [ { "Action": "iam:*", "Resource": "*", "Effect": "Allow" } ] } "IsDefaultVersion": "false" } }
新旧の内容を取得するため、異なるバージョンを指定して2回実行しています。
diff を実行する
以下の条件で diff を実行します。
- context形式で差分の前後の行の出力はなし(
-C 0
) - ラベルとしてポリシーバージョンとバージョンの作成日時を表示
- 一つ前のバージョン、デフォルトバージョンの順で比較
diff -C 0 --label "Version$BEFORE_VERSION:$BEFORE_DATE" --label "Version$VERSION:$AFTER_DATE" /tmp/policy_before /tmp/policy_after
ラベルを指定している箇所がちょっとしたお気に入りです。
diff の内容をカスタマイズしたい場合は以下を参考にどうぞ。
やりたかったけど実現できなかったこと
もう少し違う形にしたかったけど断念した集です。回避策を思いついた方は教えていただけると嬉しいです。
ポリシー ARN でなくポリシー名で指定する
当初はエイリアス側で--policy-arn arn:aws:iam::aws:policy/$1
のような形式で指定していました。エイリアスコマンドの引数としてポリシー ARN すべてを打ち込むよりは、ポリシー名だけの方が楽だと思ったためです。
その場合、パス(/service-role/
や/job-function/
など)を持つポリシーに対応できないことに気づきました。回避方法も思いつかなかったので、大人しく ARN すべてを渡す方式にしました。
マネジメントコンソールからポリシー ARN をコピーできますので、こちらをご活用ください。
tmpファイルを作成しない
今回は一度ポリシードキュメントを tmp ファイルを作成してから最後にそれを削除しています。ファイルの作成をせず、環境変数の中身を比較する方式を取れればそれが理想でした。
最初期は以下のようなエイリアスを書いていました。
[toplevel] diff = !f() { VERSION=$(aws iam get-policy --policy-arn $1 --query 'Policy.DefaultVersionId' --output text | tr -d "v") BEFORE_VERSION=$((VERSION-1)) BEFORE=$(aws iam get-policy-version --policy-arn $1 --version-id v$BEFORE_VERSION --query PolicyVersion.Document) AFTER=$(aws iam get-policy-version --policy-arn $1 --version-id v$VERSION --query PolicyVersion.Document) diff <(echo $BEFORE) <(echo $AFTER) }; f
この状態でエイリアスを実行すると以下のようなエラーが出ます。
$ aws diff arn:aws:iam::aws:policy/ReadOnlyAccess /bin/sh: -c: line 5: syntax error near unexpected token `(' /bin/sh: -c: line 5: `diff <(echo $BEFORE) <(echo $AFTER)'
こちらの記事にあるような事象だろうというところまで理解しましたが、解決策まで思いつかなかったので諦めました。
バージョンが一つしかないポリシーでのハンドリング
デフォルトバージョンが v1 のポリシーを引数として渡すと、「ひとつ前のバージョン」に対するaws iam get-policy-version
の段階でエラーが出ます。
$ aws diff arn:aws:iam::aws:policy/AdministratorAccess An error occurred (ValidationError) when calling the GetPolicyVersion operation: 1 validation error detected: Value 'v0' at 'versionId' failed to satisfy constraint: Member must satisfy regular expression pattern: v[1-9][0-9]*(\.[A-Za-z0-9-]*)? *** Version0: --- Version1:"2015-02-06T18:39:46+00:00" *************** *** 0 **** --- 1,10 ---- + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "*", + "Resource": "*" + } + ] + }
if 文などで回避してあげればスマートなのですが、まぁいいか……という感じでそのままにしています。
終わりに
管理ポリシーの差分を確認する AWS CLI エイリアスを作ってみました。
- 一つ前のバージョンのポリシードキュメントを VS Code にペーストする
- デフォルトバージョンのポリシードキュメントをコピーする
- VS Code のコマンドパレットから
File: Compare Active File with Clipboard
を行う
……という手順を頑張っておこなっていたのですが、耐えきれなくなったので楽をしてみました。いつかマネジメントコンソールで差分比較の機能が実装されることを夢見ながら、しばらくはこれで耐え凌ごうと思います。
同じような悩みを抱えている方の参考になれば幸いです。
以上、 チバユキ (@batchicchi) がお送りしました。